#include "modelwidget.h"
#include <QHBoxLayout>
#include <QUrl>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DRender/QCamera>
//#include <Qt3DRender/QPointLight>
#include <Qt3DRender/QDirectionalLight>
#include <Qt3DExtras/QPhongMaterial>
//#include <Qt3DExtras/QOrbitCameraController>
//#include <Qt3DExtras/QFirstPersonCameraController>
#include <QScreen>
#include "trackballcameracontroller.h"
#include <Qt3DExtras/QForwardRenderer>
#include <Qt3DExtras/QCuboidMesh>
#include <Qt3DExtras/QCuboidGeometry>
#include <QLabel>
#include <QLineEdit>
#include <QSlider>
#include <Qt3DRender/QAttribute>
#include <Qt3DRender/QSceneLoader>

ModelWidget::ModelWidget(QWidget *parent) : QWidget(parent),
    rootEntity(nullptr), camera(nullptr), cuboidEntity(nullptr), cuboidTransform(nullptr),
    modelEntity(nullptr), modelTransform(nullptr), modelCheckBox(nullptr)
{
    // 设置背景为白色
//    setPalette(QPalette(Qt::white));
//    setAutoFillBackground(true);

    connect(this, SIGNAL(cuboidScaleChanged(float)), parent, SLOT(onCuboidScaleChanged(float)));
    connect(this, SIGNAL(cuboidRotationChanged(float, float, float)), parent, SLOT(onCuboidRotationChanged(float, float, float)));
    connect(this, SIGNAL(modelScaleChanged(float)), parent, SLOT(onModelScaleChanged(float)));
    connect(this, SIGNAL(modelRotationChanged(float, float, float)), parent, SLOT(onModelRotationChanged(float, float, float)));

    QWidget *modelPanel = createModelPanel();
    QWidget *opPanel = createOpPanel();

    QHBoxLayout *hLayout = new QHBoxLayout(this);
    hLayout->setMargin(10);
    hLayout->setSpacing(5);
    hLayout->addWidget(modelPanel, 1);
    hLayout->addWidget(opPanel);
}

ModelWidget::~ModelWidget()
{
}

//void StlWidget::resizeEvent(QResizeEvent *event)
//{
//    resizeView(this->size());
//}

//void StlWidget::resizeView(QSize size)
//{
//    if (container != nullptr)
//    {
//        container->resize(size);
//    }
//}

QWidget *ModelWidget::createModelPanel()
{
    auto view = new Qt3DExtras::Qt3DWindow();

    // background color
    view->defaultFrameGraph()->setClearColor(QColor(QRgb(0x4d4d4f)));

    auto container = createWindowContainer(view, this);

    QSize screenSize = view->screen()->size();
    qDebug() << "screen size: " << screenSize;

    container->setMinimumSize(QSize(screenSize.width() / 2, screenSize.height() / 1.5));
    container->setMaximumSize(screenSize);
    container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    container->setFocusPolicy(Qt::StrongFocus);

    rootEntity = new Qt3DCore::QEntity();
    camera = view->camera();

    //观测视角
//    在显示3D图形的过程当中，摄像机是必不可少的，只有摄像机摆放的合适人眼才能看到3D建模的样子。在Qt当中三维图形将实体添加到世界坐标当中然后通过投影的方式去投射到摄像机位置（也就相当于人眼），其中投影到镜头如下面的函数所示。
//    lens表示了镜头，这个函数有着四个参数，第一个参数是视觉域，第二个是分辨率（这里选择了16比9），第三个参数是近平面摆放位置，最后一个是远平面放置位置，后两个参数的选择当中要特别注意，只有在远近平面之间的物体才会显示,所以要是想全部显示出所加入的实体，那么近平面就要足够近，远平面就要足够远。
    camera->lens()->setPerspectiveProjection(45.0f, 16.0f / 9.0f, 0.1f, 1000.0f);
//    确定摄像机摆放的位置，确定向上的单位向量和确定观察的中心
    camera->setPosition(QVector3D(0, 0, 20.0f));
    camera->setUpVector(QVector3D(0, 1, 0)); // /UpVector表示了你在建立视点坐标系时的摄像机向上的方向，决定了坐标系该轴的正值延伸方向(取±1）。
    camera->setViewCenter(QVector3D(0, 0, 0));

//    Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(rootEntity); //第一人称相机控制器（类似cs）
//    Qt3DExtras::QOrbitCameraController *camController = new Qt3DExtras::QOrbitCameraController(rootEntity); //轨道相机控制器（围绕物体旋转）
    auto camController = new TrackballCameraController(rootEntity);
    camController->setCamera(camera);

    auto lightEntity = new Qt3DCore::QEntity(rootEntity);
//    Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity); // 点光源
    auto light = new Qt3DRender::QDirectionalLight(lightEntity);
//    light->setColor("white");
//    light->setIntensity(0.8f);
    lightEntity->addComponent(light);

    auto lightTransform = new Qt3DCore::QTransform(lightEntity);
    lightTransform->setTranslation(camera->position()); // x表示左右，y是上下，z表示前后（左正右负，上正下负，后正前负）
//    lifht1Transform->setTranslation(QVector3D(0.0f, 10000.0f, 0.0f));//向y轴正方向平移十个单位
    lightEntity->addComponent(lightTransform);

    view->setRootEntity(rootEntity);

    createCuboid(container->width(), container->height());
    createModel(container->width(), container->height());

    return container;
}

void ModelWidget::createCuboid(int containerWidth, int containerHeight)
{
    qDebug() << "container width: " << containerWidth
             << "container height: " << containerHeight;

    auto cuboidMesh = new Qt3DExtras::QCuboidMesh();
    cuboidTransform = new Qt3DCore::QTransform();

    const float scale = 10.0f;
    cuboidTransform->setScale(scale);
    emit cuboidScaleChanged(scale);

    cuboidTransform->setTranslation(QVector3D(0.0f, 0.0f, 0.0f));

    const float rotationX = 45.0f;
    cuboidTransform->setRotationX(rotationX);
    emit cuboidRotationChanged(rotationX, 0, 0);

    auto cuboidMaterial = new Qt3DExtras::QPhongMaterial();
//    cuboidMaterial->setDiffuse(QColor(0xff, 0xff, 0xff, 0xff));
    cuboidMaterial->setAmbient(QColor(0xff, 0xff, 0xff));
    cuboidMaterial->setShininess(1000.0f);  // setShiness()用于设置物体表面的粗糙/反光程度，float类型，数值越大越光滑

    cuboidEntity = new Qt3DCore::QEntity(rootEntity);
    cuboidEntity->addComponent(cuboidMesh);
    cuboidEntity->addComponent(cuboidTransform);
    cuboidEntity->addComponent(cuboidMaterial);

    qDebug() << "cube translation: " << cuboidTransform->translation()
             << "rotation: " << cuboidTransform->rotationX()
             << cuboidTransform->rotationY()
             << cuboidTransform->rotationZ()
             << " scale3d: " << cuboidTransform->scale3D();

    qDebug() << cuboidMesh->geometry()->attributes();

    qDebug() << cuboidMesh->xExtent() << " " << cuboidMesh->xyMeshResolution() << cuboidMesh->xzMeshResolution()
             << cuboidMesh->yExtent() << " " << cuboidMesh->yzMeshResolution()
             << cuboidMesh->zExtent();
}

void ModelWidget::createModel(int containerWidth, int containerHeight)
{
    modelEntity = new Qt3DCore::QEntity(rootEntity);
    modelEntity->setEnabled(false);

//    modelMesh = new Qt3DRender::QMesh();
//    modelMesh->setMeshName("FlyingWedge");
//    modelMesh->setSource(data);

    modelTransform = new Qt3DCore::QTransform();
//    modelTransform->setScale(0.5f);
//    coreTransform->setScale3D(QVector3D(1.5, 1, 0.5));
//    coreTransform->setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), 45.0f));
//    coreTransform->setRotation(QQuaternion(1, 1.5, 1, 0).normalized());
    modelTransform->setTranslation(QVector3D(0.0f, 0.0f, 0.0f));

    auto coreMaterial = new Qt3DExtras::QPhongMaterial();
    coreMaterial->setDiffuse(QColor("yellow"));

//    modelEntity->addComponent(modelMesh);
    modelEntity->addComponent(modelTransform);
    modelEntity->addComponent(coreMaterial);

//    Qt3DInput::QInputAspect *input = new Qt3DInput::QInputAspect;
//    engine.registerAspect(input);
//    input->setCamera(camera);//使摄像机能左右转动

    modelEntity->setEnabled(false);

    qDebug() << "model translation: " << modelTransform->translation()
             << "rotation: " << modelTransform->rotationX()
             << modelTransform->rotationY()
             << modelTransform->rotationZ()
             << " scale3d: " << modelTransform->scale3D();
}

QWidget *ModelWidget::createOpPanel()
{
    QVBoxLayout *vLayout = new QVBoxLayout();

    QCheckBox *cuboidCheckBox = new QCheckBox(this);
    cuboidCheckBox->setText(QStringLiteral("Show cuboid"));
    cuboidCheckBox->setChecked(true);

    modelCheckBox = new QCheckBox(this);
    modelCheckBox->setText(QStringLiteral("Show model"));
    modelCheckBox->setChecked(false);

    QLineEdit *scaleEdit = new QLineEdit(this);

    QSlider *rotationSliderX = new QSlider(Qt::Horizontal, this);
    rotationSliderX->setTickInterval(30);
    rotationSliderX->setTickPosition(QSlider::TicksBelow);
    rotationSliderX->setMinimum(-180);
    rotationSliderX->setValue(0);
    rotationSliderX->setMaximum(180);

    QSlider *rotationSliderY = new QSlider(Qt::Horizontal, this);
    rotationSliderY->setTickInterval(30);
    rotationSliderY->setTickPosition(QSlider::TicksAbove);
    rotationSliderY->setMinimum(-180);
    rotationSliderY->setValue(0);
    rotationSliderY->setMaximum(180);

    QSlider *rotationSliderZ = new QSlider(Qt::Horizontal, this);
    rotationSliderZ->setTickInterval(30);
    rotationSliderZ->setTickPosition(QSlider::TicksAbove);
    rotationSliderZ->setMinimum(-180);
    rotationSliderZ->setValue(0);
    rotationSliderZ->setMaximum(180);

    vLayout->addWidget(cuboidCheckBox, 0, Qt::AlignTop);
    vLayout->addWidget(modelCheckBox, 0, Qt::AlignTop);

    vLayout->addWidget(new QLabel(QStringLiteral("缩放")));
    vLayout->addWidget(scaleEdit, 0, Qt::AlignTop);

    vLayout->addWidget(new QLabel(QStringLiteral("Axis X rotation")));
    vLayout->addWidget(rotationSliderX, 0, Qt::AlignTop);

    vLayout->addWidget(new QLabel(QStringLiteral("Axis Y rotation")));
    vLayout->addWidget(rotationSliderY, 0, Qt::AlignTop);

    vLayout->addWidget(new QLabel(QStringLiteral("Axis Z rotation")));
    vLayout->addWidget(rotationSliderZ, 1, Qt::AlignTop);

    connect(cuboidCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setCuboidEnabled(int)));
    connect(modelCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setModelEnabled(int)));
    connect(scaleEdit, SIGNAL(textChanged(QString)), this, SLOT(scale(QString)));
    connect(rotationSliderX, SIGNAL(valueChanged(int)), this, SLOT(rotateX(int)));
    connect(rotationSliderY, SIGNAL(valueChanged(int)), this, SLOT(rotateY(int)));
    connect(rotationSliderZ, SIGNAL(valueChanged(int)), this, SLOT(rotateZ(int)));

    QWidget *widget = new QWidget(this);
    widget->setLayout(vLayout);
    return widget;
}

void ModelWidget::onFileOpen(const QString &filePath)
{
//    modelEntity->setEnabled(false);

//    auto coreComponents = modelEntity->components();
//    for (int i = 0; i < coreComponents.size(); ++i)
//    {
//        auto component = coreComponents[i];
//        modelEntity->removeComponent(component);
//        delete component;
//    }

//    QUrl data = QUrl::fromLocalFile(filePath);

//    auto modelMesh = new Qt3DRender::QMesh();
////    modelMesh->setMeshName("FlyingWedge");
//    modelMesh->setSource(data);

//    modelTransform = new Qt3DCore::QTransform();
////    modelTransform->setScale(0.5f);
////    coreTransform->setScale3D(QVector3D(1.5, 1, 0.5));
////    coreTransform->setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), 45.0f));
////    coreTransform->setRotation(QQuaternion(1, 1.5, 1, 0).normalized());
//    modelTransform->setTranslation(QVector3D(0.0f, 0.0f, 0.0f));

//    auto coreMaterial = new Qt3DExtras::QPhongMaterial();
//    coreMaterial->setDiffuse(QColor("yellow"));

//    modelEntity->addComponent(modelMesh);
//    modelEntity->addComponent(modelTransform);
//    modelEntity->addComponent(coreMaterial);

////    Qt3DInput::QInputAspect *input = new Qt3DInput::QInputAspect;
////    engine.registerAspect(input);
////    input->setCamera(camera);//使摄像机能左右转动

//    modelEntity->setEnabled(true);
//    modelCheckBox->setChecked(true);

//    qDebug() << "model translation: " << modelTransform->translation()
//             << "rotation: " << modelTransform->rotationX()
//             << modelTransform->rotationY()
//             << modelTransform->rotationZ()
//             << " scale3d: " << modelTransform->scale3D();

//    QUrl data = QUrl::fromLocalFile(filePath);
//    modelMesh->setSource(data);

//    auto geometry = new Qt3DRender::QGeometry(); // todo 模型大小
//    modelMesh->setGeometry(geometry);

    Qt3DRender::QSceneLoader *loader = new Qt3DRender::QSceneLoader(modelEntity);

    QUrl url = QUrl::fromLocalFile(filePath);

    QObject::connect(loader, &Qt3DRender::QSceneLoader::statusChanged,
                     this, [](Qt3DRender::QSceneLoader::Status s)
    {
        qDebug() << s;
        return false;
    });


    loader->setSource(url);

    modelEntity->addComponent(loader);

    modelEntity->setEnabled(true);
    modelCheckBox->setChecked(true);
}

void ModelWidget::setCuboidEnabled(int enabled)
{
    if (cuboidEntity != nullptr)
    {
        cuboidEntity->setEnabled(enabled);
    }
}

void ModelWidget::setModelEnabled(int enabled)
{
    if (modelEntity != nullptr)
    {
        modelEntity->setEnabled(enabled);
    }
}

void ModelWidget::scale(const QString &text)
{
    const float scale = text.toFloat();

    if (cuboidTransform != nullptr)
    {
        cuboidTransform->setScale(scale);
        emit cuboidScaleChanged(scale);
    }

    if (modelTransform != nullptr)
    {
        modelTransform->setScale(scale);
        emit modelScaleChanged(scale);
    }
}

void ModelWidget::rotateX(int rotation)
{
    if (cuboidTransform != nullptr)
    {
        cuboidTransform->setRotationX(rotation);
        emit cuboidRotationChanged(cuboidTransform->rotationX(), cuboidTransform->rotationY(), cuboidTransform->rotationZ());
    }

    if (modelTransform != nullptr)
    {
        modelTransform->setRotationX(rotation);
        emit modelRotationChanged(modelTransform->rotationX(), modelTransform->rotationY(), modelTransform->rotationZ());
    }
}

void ModelWidget::rotateY(int rotation)
{
    if (cuboidTransform != nullptr)
    {
        cuboidTransform->setRotationY(rotation);
        emit cuboidRotationChanged(cuboidTransform->rotationX(), cuboidTransform->rotationY(), cuboidTransform->rotationZ());
    }

    if (modelTransform != nullptr)
    {
        modelTransform->setRotationY(rotation);
        emit modelRotationChanged(modelTransform->rotationX(), modelTransform->rotationY(), modelTransform->rotationZ());
    }
}

void ModelWidget::rotateZ(int rotation)
{
    if (cuboidTransform != nullptr)
    {
        cuboidTransform->setRotationZ(rotation);
        emit cuboidRotationChanged(cuboidTransform->rotationX(), cuboidTransform->rotationY(), cuboidTransform->rotationZ());
    }

    if (modelTransform != nullptr)
    {
        modelTransform->setRotationZ(rotation);
        emit modelRotationChanged(modelTransform->rotationX(), modelTransform->rotationY(), modelTransform->rotationZ());
    }
}
